#ifndef __MINITYPES_H__
#define __MINITYPES_H__

#include "./minitype.h"

namespace MiniUI
{
namespace Type
{

enum FontStyle
{
    FONTSTYLE_NORMAL = 0,
    FONTSTYLE_BOLD = 0x01,
    FONTSTYLE_ITALIC = 0x02,
    FONTSTYLE_UNDERLINE = 0x04,
    FONTSTYLE_STRIKE = 0x08
};

enum TextAlign
{
    TEXTALIGN_TOP = 0,
    TEXTALIGN_LEFT = 0,
    TEXTALIGN_CENTER = 0x01,
    TEXTALIGN_RIGHT = 0x02,
    TEXTALIGN_VCENTER = 0x04,
    TEXTALIGN_BOTTOM = 0x08
};

class MiniSize;
class MiniPoint;
class MiniRect;
class MiniARGB;

class MiniSize : public miniSize
{
public:
    MiniSize();
    MiniSize(int x, int y);
    MiniSize(const miniSize& size);
    bool operator ==(miniSize size) const;
    bool operator !=(miniSize size) const;
    void operator +=(miniSize size);
    void operator -=(miniSize size);
    void SetSize(int x, int y);
    MiniSize operator +(miniSize size) const;
    MiniSize operator -(miniSize size) const;
    MiniSize operator -() const;
    MiniPoint operator +(miniPoint pt) const;
    MiniPoint operator -(miniPoint pt) const;
    MiniRect operator +(const miniRect* pRect) const;
    MiniRect operator -(const miniRect* pRect) const;
};

class MiniPoint : public miniPoint
{
public:
    MiniPoint();
    MiniPoint(int ptX, int ptY);
    MiniPoint(const miniPoint& pt);
    void Offset(int xOffset, int yOffset);
    void Offset(miniPoint pt);
    void Offset(miniSize size);
    bool operator ==(miniPoint pt) const;
    bool operator !=(miniPoint pt) const;
    void operator +=(miniSize size);
    void operator -=(miniSize size);
    void operator +=(miniPoint pt);
    void operator -=(miniPoint pt);
    void SetPoint(int ptX, int ptY);
    MiniPoint operator +(miniSize size) const;
    MiniPoint operator -(miniSize size) const;
    MiniPoint operator -() const;
    MiniPoint operator +(miniPoint pt) const;
    MiniSize operator -(miniPoint pt) const;
    MiniRect operator +(const miniRect* pRect) const;
    MiniRect operator -(const miniRect* pRect) const;
};

class MiniRect : public miniRect
{
public:
    MiniRect();
    MiniRect(int l, int t, int r, int b);
    MiniRect(const miniRect& srcRect);
    MiniRect(const miniRect* pSrcRect);
    MiniRect(miniPoint pt, miniSize size);
    MiniRect(miniPoint topLeft, miniPoint bottomRight);
    int Width() const;
    int Height() const;
    MiniSize Size() const;
    MiniPoint& TopLeft();
    MiniPoint& BottomRight();
    const MiniPoint& TopLeft() const;
    const MiniPoint& BottomRight() const;
    MiniPoint CenterPoint() const;
    operator miniRect*();
    operator const miniRect*() const;
    bool IsRectEmpty() const;
    bool IsRectNull() const;
    bool PtInRect(miniPoint pt) const;
    void SetRect(int x1, int y1, int x2, int y2);
    void SetRect(miniPoint topLeft, miniPoint bottomRight);
    void SetRectEmpty();
    void CopyRect(const miniRect* pSrcRect);
    bool EqualRect(const miniRect* pRect) const;
    void InflateRect(int x, int y);
    void InflateRect(miniSize size);
    void InflateRect(const miniRect* pRect);
    void InflateRect(int l, int t, int r, int b);
    void DeflateRect(int x, int y);
    void DeflateRect(miniSize size);
    void DeflateRect(const miniRect* pRect);
    void DeflateRect(int l, int t, int r, int b);
    void OffsetRect(int x, int y);
    void OffsetRect(miniSize size);
    void OffsetRect(miniPoint pt);
    void NormalizeRect();
    void MoveToY(int y);
    void MoveToX(int x);
    void MoveToXY(int x, int y);
    void MoveToXY(miniPoint pt);
    bool IntersectRect(const miniRect* pRect1, const miniRect* pRect2);
    bool UnionRect(const miniRect* pRect1, const miniRect* pRect2);
    bool SubtractRect(const miniRect* pRect1, const miniRect* pRect2);

    void operator =(const miniRect& srcRect);
    bool operator ==(const miniRect& rect) const;
    bool operator !=(const miniRect& rect) const;
    void operator +=(miniPoint pt);
    void operator +=(miniSize size);
    void operator +=(const miniRect* pRect);
    void operator -=(miniPoint pt);
    void operator -=(miniSize size);
    void operator -=(const miniRect* pRect);
    void operator &=(const miniRect& rect);
    void operator |=(const miniRect& rect);
    MiniRect operator +(miniPoint pt) const;
    MiniRect operator -(miniPoint pt) const;
    MiniRect operator +(const miniRect* pRect) const;
    MiniRect operator +(miniSize size) const;
    MiniRect operator -(miniSize size) const;
    MiniRect operator -(const miniRect* lpRect) const;
    MiniRect operator &(const miniRect& rect) const;
    MiniRect operator |(const miniRect& rect) const;
};

class MiniARGB : public miniARGB
{
public:
    MiniARGB();
    MiniARGB(byte alpha, byte red, byte green, byte blue);
    MiniARGB(uint32 argb);
    MiniARGB(const miniARGB& srcARGB);
    bool operator ==(const miniARGB& otherARGB) const;
    bool operator !=(const miniARGB& otherARGB) const;
    void SetARGB(byte alpha, byte red, byte green, byte blue);
};

//MiniSize

inline MiniSize::MiniSize() 
{
    cx = 0;
    cy = 0;
}

inline MiniSize::MiniSize(int x, int y)
{
    cx = x;
    cy = y;
}

inline MiniSize::MiniSize(const miniSize& size)
{
    *(miniSize*)this = size;
}

inline bool MiniSize::operator ==(miniSize size) const
{
    return (cx == size.cx && cy == size.cy);
}

inline bool MiniSize::operator !=(miniSize size) const
{
    return (cx != size.cx || cy != size.cy);
}

inline void MiniSize::operator +=(miniSize size)
{
    cx += size.cx;
    cy += size.cy;
}

inline void MiniSize::operator -=(miniSize size)
{
    cx -= size.cx;
    cy -= size.cy;
}

inline void MiniSize::SetSize(int x, int y)
{
    cx = x;
    cy = y;
}

inline MiniSize MiniSize::operator +(miniSize size) const
{
    return MiniSize(cx + size.cx, cy + size.cy);
}

inline MiniSize MiniSize::operator -(miniSize size) const
{
    return MiniSize(cx - size.cx, cy - size.cy);
}

inline MiniSize MiniSize::operator -() const
{
    return MiniSize(-cx, -cy);
}

inline MiniPoint MiniSize::operator +(miniPoint pt) const
{
    return MiniPoint(cx + pt.x, cy + pt.y);
}

inline MiniPoint MiniSize::operator -(miniPoint pt) const
{
    return MiniPoint(cx - pt.x, cy - pt.y);
}

inline MiniRect MiniSize::operator +(const miniRect* pRect) const
{
    return MiniRect(pRect) + *this;
}

inline MiniRect MiniSize::operator -(const miniRect* pRect) const
{
    return MiniRect(pRect) - *this;
}

//MiniPoint

inline MiniPoint::MiniPoint()
{
    x = 0;
    y = 0;
}

inline MiniPoint::MiniPoint(int ptX, int ptY)
{
    x = ptX;
    y = ptY;
}

inline MiniPoint::MiniPoint(const miniPoint& pt)
{
    *(miniPoint*)this = pt;
}

inline void MiniPoint::Offset(int xOffset, int yOffset)
{
    x += xOffset;
    y += yOffset;
}

inline void MiniPoint::Offset(miniPoint pt)
{
    x += pt.x;
    y += pt.y;
}

inline void MiniPoint::Offset(miniSize size)
{
    x += size.cx;
    y += size.cy;
}

inline bool MiniPoint::operator ==(miniPoint pt) const
{
    return (x == pt.x && y == pt.y);
}

inline bool MiniPoint::operator !=(miniPoint pt) const
{
    return (x != pt.x || y != pt.y);
}

inline void MiniPoint::operator +=(miniSize size)
{
    x += size.cx;
    y += size.cy;
}

inline void MiniPoint::operator -=(miniSize size)
{
    x -= size.cx;
    y -= size.cy;
}

inline void MiniPoint::operator +=(miniPoint pt)
{
    x += pt.x;
    y += pt.y;
}

inline void MiniPoint::operator -=(miniPoint pt)
{
    x -= pt.x;
    y -= pt.y;
}

inline void MiniPoint::SetPoint(int ptX, int ptY)
{
    x = ptX;
    y = ptY;
}

inline MiniPoint MiniPoint::operator +(miniSize size) const
{
    return MiniPoint(x + size.cx, y + size.cy);
}

inline MiniPoint MiniPoint::operator -(miniSize size) const
{
    return MiniPoint(x - size.cx, y - size.cy);
}

inline MiniPoint MiniPoint::operator -() const
{
    return MiniPoint(-x, -y);
}

inline MiniPoint MiniPoint::operator +(miniPoint pt) const
{
    return MiniPoint(x + pt.x, y + pt.y);
}

inline MiniSize MiniPoint::operator -(miniPoint pt) const
{
    return MiniSize(x - pt.x, y - pt.y);
}

inline MiniRect MiniPoint::operator +(const miniRect* pRect) const
{
    return MiniRect(pRect) + *this;
}

inline MiniRect MiniPoint::operator -(const miniRect* pRect) const
{
    return MiniRect(pRect) - *this;
}

//MiniRect

inline MiniRect::MiniRect()
{
    left = 0;
    top = 0;
    right = 0;
    bottom = 0;
}

inline MiniRect::MiniRect(int l, int t, int r, int b)
{
    left = l;
    top = t;
    right = r;
    bottom = b;
}

inline MiniRect::MiniRect(const miniRect& srMiniRect)
{
    *(miniRect*)this = srMiniRect;
}

inline MiniRect::MiniRect(const miniRect* pSrMiniRect)
{
    *(miniRect*)this = *pSrMiniRect;
}

inline MiniRect::MiniRect(miniPoint pt, miniSize size)
{
    right = (left = pt.x) + size.cx;
    bottom = (top = pt.y) + size.cy;
}

inline MiniRect::MiniRect(miniPoint topLeft, miniPoint bottomRight)
{
    left = topLeft.x;
    top = topLeft.y;
    right = bottomRight.x;
    bottom = bottomRight.y;
}

inline int MiniRect::Width() const
{
    return right - left;
}

inline int MiniRect::Height() const
{
    return bottom - top;
}

inline MiniSize MiniRect::Size() const
{
    return MiniSize(right - left, bottom - top);
}

inline MiniPoint& MiniRect::TopLeft()
{
    return *((MiniPoint*)this);
}

inline MiniPoint& MiniRect::BottomRight()
{
    return *((MiniPoint*)this + 1);
}

inline const MiniPoint& MiniRect::TopLeft() const
{
    return *((MiniPoint*)this);
}

inline const MiniPoint& MiniRect::BottomRight() const
{
    return *((MiniPoint*)this + 1);
}

inline MiniPoint MiniRect::CenterPoint() const
{
    return MiniPoint((left + right) / 2, (top + bottom) / 2);
}

inline MiniRect::operator miniRect*()
{
    return this;
}

inline MiniRect::operator const miniRect*() const
{
    return this;
}

inline bool MiniRect::IsRectEmpty() const
{
    return (left == right || top == bottom);
}

inline bool MiniRect::IsRectNull() const
{
    return (left == 0 && right == 0 && top == 0 && bottom == 0);
}

inline bool MiniRect::PtInRect(miniPoint pt) const
{
    return (pt.x >= left && pt.x < right && pt.y >= top && pt.y < bottom);
}


inline void MiniRect::SetRect(int x1, int y1, int x2, int y2)
{
    left = x1;
    top = y1;
    right = x2;
    bottom = y2;
}

inline void MiniRect::SetRect(miniPoint topLeft, miniPoint bottomRight)
{
    SetRect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
}

inline void MiniRect::SetRectEmpty()
{
    left = 0;
    top = 0;
    right = 0;
    bottom = 0;
}

inline void MiniRect::CopyRect(const miniRect* pSrMiniRect)
{
    *(miniRect*)this = *pSrMiniRect;
}

inline bool MiniRect::EqualRect(const miniRect* pRect) const
{
    return (left == pRect->left && top == pRect->top && right == pRect->right && bottom == pRect->bottom);
}

inline void MiniRect::InflateRect(int x, int y)
{
    left -= x;
    top -= y;
    right += x;
    bottom += y;
}

inline void MiniRect::InflateRect(miniSize size)
{
    InflateRect(size.cx, size.cy);
}

inline void MiniRect::InflateRect(const miniRect* pRect)
{
    left -= pRect->left;
    top -= pRect->top;
    right += pRect->right;
    bottom += pRect->bottom;
}

inline void MiniRect::InflateRect(int l, int t, int r, int b)
{
    left -= l;
    top -= t;
    right += r;
    bottom += b;
}

inline void MiniRect::DeflateRect(int x, int y)
{
    InflateRect(-x, -y);
}

inline void MiniRect::DeflateRect(miniSize size)
{
    InflateRect(-size.cx, -size.cy);
}

inline void MiniRect::DeflateRect(const miniRect* lpRect)
{
    left += lpRect->left;
    top += lpRect->top;
    right -= lpRect->right;
    bottom -= lpRect->bottom;
}

inline void MiniRect::DeflateRect(int l, int t, int r, int b)
{
    left += l;
    top += t;
    right -= r;
    bottom -= b;
}

inline void MiniRect::OffsetRect(int x, int y)
{
    left += x;
    top += y;
    right += x;
    bottom += y;
}

inline void MiniRect::OffsetRect(miniSize size)
{
    OffsetRect(size.cx, size.cy);
}

inline void MiniRect::OffsetRect(miniPoint point)
{
    OffsetRect(point.x, point.y);
}

inline void MiniRect::NormalizeRect()
{
    int nTemp;
    if (left > right)
    {
        nTemp = left;
        left = right;
        right = nTemp;
    }
    if (top > bottom)
    {
        nTemp = top;
        top = bottom;
        bottom = nTemp;
    }
}

inline void MiniRect::MoveToY(int y)
{
    bottom = Height() + y;
    top = y;
}

inline void MiniRect::MoveToX(int x)
{
    right = Width() + x;
    left = x;
}

inline void MiniRect::MoveToXY(int x, int y)
{
    MoveToX(x);
    MoveToY(y);
}

inline void MiniRect::MoveToXY(miniPoint pt)
{
    MoveToX(pt.x);
    MoveToY(pt.y);
}

inline bool MiniRect::IntersectRect(const miniRect* pRect1, const miniRect* pRect2)
{
    int maxLeft = max(pRect1->left, pRect2->left);
    int maxTop = max(pRect1->top, pRect2->top);
    int minRight = min(pRect1->right, pRect2->right);
    int minBottom = min(pRect1->bottom, pRect2->bottom);
    if (maxLeft < minRight && maxTop < minBottom)
    {
        left = maxLeft;
        top = maxTop;
        right = minRight;
        bottom = minBottom;
        return true;
    }
    else
    {
        SetRectEmpty();
        return false;
    }
}

inline bool MiniRect::UnionRect(const miniRect* pRect1, const miniRect* pRect2)
{
    if (pRect1->left == pRect1->right || pRect1->top == pRect1->bottom)
    {
        if (pRect2->left == pRect2->right || pRect2->top == pRect2->bottom)
        {
            SetRectEmpty();
            return false;
        }
        else
        {
            *(miniRect*)this = *pRect2;
            return true;
        }
    }
    else if (pRect2->left == pRect2->right || pRect2->top == pRect2->bottom)
    {
        if (pRect1->left == pRect1->right || pRect1->top == pRect1->bottom)
        {
            SetRectEmpty();
            return false;
        }
        else
        {
            *(miniRect*)this = *pRect1;
            return true;
        }
    }
    int minLeft = min(pRect1->left, pRect2->left);
    int minTop = min(pRect1->top, pRect2->top);
    int maxRight = max(pRect1->right, pRect2->right);
    int maxBottom = max(pRect1->bottom, pRect2->bottom);
    if (minLeft < maxRight && minTop < maxBottom)
    {
        left = minLeft;
        top = minTop;
        right = maxRight;
        bottom = maxBottom;
        return true;
    }
    else
    {
        SetRectEmpty();
        return false;
    }
}


inline bool MiniRect::SubtractRect(const miniRect* pRect1, const miniRect* pRect2)
{
    if (pRect1->left == pRect1->right || pRect1->top == pRect1->bottom)
    {
        SetRectEmpty();
        return false;
    }
    // w&o one of four borders of pRect2 crosses pRect1 subtraction suc
    int nCount = 0;
    // topleft-topright
    if (pRect2->top > pRect1->top && pRect2->top < pRect1->bottom
        && pRect2->left <= pRect1->left && pRect2->right >= pRect1->right)
    {
        nCount++;
    }
    // bottomleft-bottomright
    if (pRect2->bottom > pRect1->top && pRect2->bottom < pRect1->bottom
        && pRect2->left <= pRect1->left && pRect2->right >= pRect1->right)
    {
        nCount++;
    }
    // lefttop-leftbottom
    if (pRect2->left > pRect1->left && pRect2->left < pRect1->right
        && pRect2->top <= pRect1->top && pRect2->bottom >= pRect1->bottom)
    {
        nCount++;
    }
    // righttop-rightbottom
    if (pRect2->right > pRect1->left && pRect2->right < pRect1->right
        && pRect2->top <= pRect1->top && pRect2->bottom >= pRect1->bottom)
    {
        nCount++;
    }

    if (nCount == 0)
    {
        if (pRect2->left <= pRect1->left && pRect2->right >= pRect1->right
            && pRect2->top <= pRect1->top && pRect2->bottom >= pRect1->bottom)
        {
            SetRectEmpty();
            return false;
        }
        else
        {
            *(miniRect*)this = *pRect1;
            return true;
        }
    }
    else if (nCount == 1)
    {
        // topleft-topright
        if (pRect2->top > pRect1->top && pRect2->top < pRect1->bottom
            && pRect2->left <= pRect1->left && pRect2->right >= pRect1->right)
        {
            *(miniRect*)this = *pRect1;
            bottom = pRect2->top;
        }
        // bottomleft-bottomright
        else if (pRect2->bottom > pRect1->top && pRect2->bottom < pRect1->bottom
            && pRect2->left <= pRect1->left && pRect2->right >= pRect1->right)
        {
            *(miniRect*)this = *pRect1;
            top = pRect2->bottom;
        }
        // lefttop-leftbottom
        else if (pRect2->left > pRect1->left && pRect2->left < pRect1->right
            && pRect2->top <= pRect1->top && pRect2->bottom >= pRect1->bottom)
        {
            *(miniRect*)this = *pRect1;
            right = pRect2->left;
        }
        // righttop-rightbottom
        else if (pRect2->right > pRect1->left && pRect2->right < pRect1->right
            && pRect2->top <= pRect1->top && pRect2->bottom >= pRect1->bottom)
        {
            *(miniRect*)this = *pRect1;
            left = pRect2->right;
        }
        return true;
    }
    else    // nCount > 1
    {
        *(miniRect*)this = *pRect1;
        return true;
    }
}


inline void MiniRect::operator =(const miniRect& srMiniRect)
{
    CopyRect(&srMiniRect);
}

inline bool MiniRect::operator ==(const miniRect& rect) const
{
    return EqualRect(&rect);
}

inline bool MiniRect::operator !=(const miniRect& rect) const
{
    return !EqualRect(&rect);
}

inline void MiniRect::operator +=(miniPoint point)
{
    OffsetRect(point.x, point.y);
}

inline void MiniRect::operator +=(miniSize size)
{
    OffsetRect(size.cx, size.cy);
}

inline void MiniRect::operator +=(const miniRect* pRect)
{
    InflateRect(pRect);
}

inline void MiniRect::operator -=(miniPoint point)
{
    OffsetRect(-point.x, -point.y);
}

inline void MiniRect::operator -=(miniSize size)
{
    OffsetRect(-size.cx, -size.cy);
}

inline void MiniRect::operator -=(const miniRect* pRect)
{
    DeflateRect(pRect);
}

inline void MiniRect::operator &=(const miniRect& rect)
{
    IntersectRect(this, &rect);
}

inline void MiniRect::operator |=(const miniRect& rect)
{
    UnionRect(this, &rect);
}

inline MiniRect MiniRect::operator +(miniPoint pt) const
{
    MiniRect rect(*this);
    rect.OffsetRect(pt.x, pt.y);
    return rect;
}

inline MiniRect MiniRect::operator -(miniPoint pt) const
{
    MiniRect rect(*this);
    rect.OffsetRect(-pt.x, -pt.y);
    return rect;
}

inline MiniRect MiniRect::operator +(const miniRect* pRect) const
{
    MiniRect rect(this);
    rect.InflateRect(pRect);
    return rect;
}

inline MiniRect MiniRect::operator +(miniSize size) const
{
    MiniRect rect(*this);
    rect.OffsetRect(size.cx, size.cy);
    return rect;
}

inline MiniRect MiniRect::operator -(miniSize size) const
{
    MiniRect rect(*this);
    rect.OffsetRect(-size.cx, -size.cy);
    return rect;
}

inline MiniRect MiniRect::operator -(const miniRect* pRect) const
{
    MiniRect rect(this);
    rect.DeflateRect(pRect);
    return rect;
}

inline MiniRect MiniRect::operator &(const miniRect& rect2) const
{
    MiniRect rect;
    rect.IntersectRect(this, &rect2);
    return rect;
}

inline MiniRect MiniRect::operator |(const miniRect& rect2) const
{
    MiniRect rect;
    rect.UnionRect(this, &rect2);
    return rect;
}

//MiniARGB

inline MiniARGB::MiniARGB()
{
    argb = 0;
}

inline MiniARGB::MiniARGB(byte alpha, byte red, byte green, byte blue)
{
     this->alpha = alpha;
     this->red = red;
     this->green = green;
     this->blue = blue;
}

inline MiniARGB::MiniARGB(uint32 argb)
{
    this->argb = argb;
}


inline MiniARGB::MiniARGB(const miniARGB& srcARGB)
{
    this->argb = srcARGB.argb;
}

inline bool MiniARGB::operator ==(const miniARGB& otherARGB) const
{
    return this->argb == otherARGB.argb;
}

inline bool MiniARGB::operator !=(const miniARGB& otherARGB) const
{
    return this->argb != otherARGB.argb;
}

inline void MiniARGB::SetARGB(byte alpha, byte red, byte green, byte blue)
{
    this->alpha = alpha;
    this->red = red;
    this->green = green;
    this->blue = blue;
}

}
}
#endif